﻿#include "stdafx.h"
#if _QG_USE_DX9
#include "qg/qgasv.h"
#include "qg_dx9_dev.h"
#include "qg_dx9_cnv.h"
#include "qg_dx9_mtrl.h"
#include "qg_trace.h"

// 재질 바인드
bool DX9Device::_BindMtrl(ksize_t count) throw()
{
	if (_sprn->bd_rasz)
	{
		_sprn->bd_rasz = false;
		_CommitRasterize(((DX9Rasz*)_sprn->m_rasz)->_data, _vprn.m_rasz_data);
	}

	if (_sprn->bd_blnd)
	{
		_sprn->bd_blnd = false;
		_CommitBlendState(((DX9Blnd*)_sprn->m_blnd)->_data, _vprn.m_blnd_data);
	}

	for (ksize_t i = 0; i < count; i++)
	{
		if (_sprn->bd_tex[i])
		{
			_sprn->bd_tex[i] = false;
			_CommitTexture(i, _sprn->m_tex[i]);
		}

		if (_sprn->bd_splr[i])
		{
			_sprn->bd_splr[i] = false;
			_CommitSampler(i, ((DX9Splr*)_sprn->m_splr[i])->_data, _vprn.m_splr_data[i]);
		}
	}

	return true;
}

// 래스터라이저
void DX9Device::_CommitRasterize(const qgRaszData& nrz, qgRaszData& prz) throw()
{
	static_assert(sizeof(DWORD) == sizeof(float), "must same storage size between DWORD & float");

	// 깊이 바이어스
	if (nrz.dbias != prz.dbias)
	{
		prz.dbias = nrz.dbias;

		_device->SetRenderState(D3DRS_DEPTHBIAS, nrz.dbias);
	}

	// 슬로프 스케일
	if (!k_eq(nrz.slope_scale, prz.slope_scale))
	{
		prz.slope_scale = nrz.slope_scale;

		_device->SetRenderState(D3DRS_SLOPESCALEDEPTHBIAS, *(DWORD*)&nrz.slope_scale);
	}

	// 채우기
	if (nrz.fill != prz.fill)
	{
		prz.fill = nrz.fill;

		_device->SetRenderState(D3DRS_FILLMODE,
			nrz.fill == QGFILL_POINT ? D3DFILL_POINT :
			nrz.fill == QGFILL_WIRE ? D3DFILL_WIREFRAME :
			D3DFILL_SOLID);
	}

	// 컬링
	if (nrz.cull != prz.cull)
	{
		prz.cull = nrz.cull;

		_device->SetRenderState(D3DRS_CULLMODE, nrz.cull);
	}

	// 깊이 쓰기
	if (nrz.dwrite != prz.dwrite)
	{
		prz.dwrite = nrz.dwrite;

		_device->SetRenderState(D3DRS_ZWRITEENABLE, nrz.dwrite ? D3DZB_TRUE : D3DZB_FALSE);
	}

	// 깊이 함수
	if (nrz.dfunc != prz.dfunc)
	{
		if (nrz.dfunc == QGCOP_NONE)
		{
			prz.dfunc = QGCOP_NONE;

			_device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
		}
		else
		{
			if (prz.dfunc == QGCOP_NONE)
				_device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE);

			prz.dfunc = nrz.dfunc;

			D3DCMPFUNC n = DX9Convert::ComparisonOp(nrz.dfunc);
			_device->SetRenderState(D3DRS_ZFUNC, n);
		}
	}
}

// 블렌드
void DX9Device::_CommitBlendState(const qgBlndData& nbd, qgBlndData& pbd) throw()
{
	// 색깔 쓰기 마스크
	if (nbd.mask != pbd.mask)
	{
		pbd.mask = nbd.mask;

		_device->SetRenderState(D3DRS_COLORWRITEENABLE, (DWORD)nbd.mask);
	}

	// 블렌드
	if (nbd.blend.op == QGBLO_NONE)
	{
		// 블렌딩 끔
		if (_vprn.m_blnd_blend)
		{
			_vprn.m_blnd_blend = false;

			_device->SetRenderState(D3DRS_ALPHABLENDENABLE, false);
		}

		if (_vprn.m_blnd_alpha)
		{
			_vprn.m_blnd_alpha = false;

			_device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, false);
		}

		pbd.blend.op = QGBLO_NONE;
		pbd.blend.src = QGBLV_NONE;
		pbd.blend.dest = QGBLV_NONE;
		pbd.alpha.op = QGBLO_NONE;
		pbd.alpha.src = QGBLV_NONE;
		pbd.alpha.dest = QGBLV_NONE;
	}
	else
	{
		if (!_vprn.m_blnd_blend)
		{
			_vprn.m_blnd_blend = true;

			_device->SetRenderState(D3DRS_ALPHABLENDENABLE, true);
		}

		if (nbd.blend.op != pbd.blend.op)
		{
			pbd.blend.op = nbd.blend.op;

			_device->SetRenderState(D3DRS_BLENDOP, DX9Convert::BlendOp(nbd.blend.op));
		}

		if (nbd.blend.src != pbd.blend.src)
		{
			pbd.blend.src = nbd.blend.src;

			_device->SetRenderState(D3DRS_SRCBLEND, DX9Convert::BlendValue(nbd.blend.src));
		}

		if (nbd.blend.dest != pbd.blend.dest)
		{
			pbd.blend.dest = nbd.blend.dest;

			_device->SetRenderState(D3DRS_DESTBLEND, DX9Convert::BlendValue(nbd.blend.dest));
		}

		if (nbd.alpha.op == QGBLO_NONE)
		{
			if (_vprn.m_blnd_alpha)
			{
				_vprn.m_blnd_alpha = false;

				_device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, false);
			}
		}
		else
		{
			if (!_vprn.m_blnd_alpha)
			{
				_vprn.m_blnd_alpha = true;

				_device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, true);
			}

			if (nbd.alpha.op != pbd.alpha.op)
			{
				pbd.alpha.op = nbd.alpha.op;

				_device->SetRenderState(D3DRS_BLENDOPALPHA, DX9Convert::BlendOp(nbd.alpha.op));
			}

			if (nbd.alpha.src != pbd.alpha.src)
			{
				pbd.alpha.src = nbd.alpha.src;

				_device->SetRenderState(D3DRS_SRCBLENDALPHA, DX9Convert::BlendValue(nbd.alpha.src));
			}

			if (nbd.alpha.dest != pbd.alpha.dest)
			{
				pbd.alpha.dest = nbd.alpha.dest;

				_device->SetRenderState(D3DRS_DESTBLENDALPHA, DX9Convert::BlendValue(nbd.alpha.dest));
			}
		}
	}
}

// 샘플러
void DX9Device::_CommitSampler(kint stage, const qgSplrData& nsp, qgSplrData& psp) throw()
{
	// 필터
	if (nsp.filt != psp.filt)
	{
		psp.filt = nsp.filt;

		D3DTEXTUREFILTERTYPE mag, min, mip;
		DX9Convert::Filter(nsp.filt, mag, min, mip);

		_device->SetSamplerState(stage, D3DSAMP_MAGFILTER, mag);
		_device->SetSamplerState(stage, D3DSAMP_MINFILTER, min);
		_device->SetSamplerState(stage, D3DSAMP_MIPFILTER, mip);
	}

	// 가로 주소 처리 (U=S=가로)
	if (nsp.addru != psp.addru)
	{
		psp.addru = nsp.addru;

		_device->SetSamplerState(stage, D3DSAMP_ADDRESSU, DX9Convert::Address(nsp.addru));
	}

	// 세로 주소 처리 (V=T=세로)
	if (nsp.addrv != psp.addrv)
	{
		psp.addrv = nsp.addrv;

		_device->SetSamplerState(stage, D3DSAMP_ADDRESSV, DX9Convert::Address(nsp.addrv));
	}

	// 깊이 주소 처리 (W=R=깊이)
	if (nsp.addrw != psp.addrw)
	{
		psp.addrw = nsp.addrw;

		_device->SetSamplerState(stage, D3DSAMP_ADDRESSW, DX9Convert::Address(nsp.addrw));
	}

	// cmpop 패스

	// 둘레
	if (nsp.border != psp.border)
	{
		psp.border = nsp.border;

		_device->SetSamplerState(stage, D3DSAMP_BORDERCOLOR, nsp.border.ToUint());
	}

	// LOD 바이어스
	if (nsp.lodrange.max > 0.0f && !k_eq(nsp.lodbias, psp.lodbias))
	{
		psp.lodbias = nsp.lodbias;

		float f = k_clamp(nsp.lodbias * 0.125f, nsp.lodrange.min, nsp.lodrange.max);
		_device->SetSamplerState(stage, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)&f);
	}
}

//
qgRasz* DX9Device::_RoamImplRasz(const qgRaszData& data)
{
	DX9Rasz* rasz = kobj_create(DX9Rasz);

	rasz->_data = data;

	return rasz;
}

//
qgBlnd* DX9Device::_RoamImplBlnd(const qgBlndData& data)
{
	DX9Blnd* blnd = kobj_create(DX9Blnd);

	blnd->_data = data;

	return blnd;
}

//
qgSplr* DX9Device::_RoamImplSplr(const qgSplrData& data)
{
	DX9Splr* splr = kobj_create(DX9Splr);

	splr->_data = data;

	return splr;
}


//////////////////////////////////////////////////////////////////////////
// 래스터라이저
KIMPL_SUBCLASS(DX9Rasz, "DX9Rasz");


//////////////////////////////////////////////////////////////////////////
// 블랜드
KIMPL_SUBCLASS(DX9Blnd, "DX9Blnd");


//////////////////////////////////////////////////////////////////////////
// 샘플러
KIMPL_SUBCLASS(DX9Splr, "DX9Splr");

#endif	// _QG_USE_DX9
